home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
pctjja86.arc
/
SCROLL.ASM
< prev
next >
Wrap
Assembly Source File
|
1984-02-13
|
9KB
|
240 lines
COMMENT * SCROLLING ROUTINE
Scrolls the entire screen any number of lines or columns
in any direction.
Its single argument gives the direction and number of lines/cols.
CALL SCROLL(ARG)
If ARG is +, scrolling is up or left.
If ARG is -, scrolling is down or right.
The magnitude of the argument gives the number of lines
and the rest of the direction information.
If |ARG| is between 1 and 25, direction is up or down.
If |ARG| is between 257 and 336, direction is left or right, and
the number of columns is |ARG|-256.
If rows or columns is greater than screen size or is zero,
then the screen is entirely blanked.
*
;
; Little data segment here for some temporary storage
;
DGROUP GROUP DATA
;
DATA SEGMENT PUBLIC 'DATA'
MODE_FLAG DB 0 ; Save mode flag returned from BIOS call
CRT_COLS DW 0 ; Save number of columns in display too.
DATA ENDS
;
CODE SEGMENT PUBLIC 'CODE'
PUBLIC SCROLL
SCROLL PROC FAR
ASSUME CS:CODE,DS:DGROUP
;
; Begin by picking up the argument from the calling routine and calling
; the BIOS for the current mode and screen size.
;
PUSH BP ; Save BP register
MOV BP,SP ; Point to stack to pick up the argument
MOV BX,6[BP] ; Get address of the argument
PUSH DS ; Save the data segment register
PUSH ES ; ES too in case using this with interpreter
PUSH [BX] ; Save the argument for later
MOV AH,15 ; Code for "return current video state"
INT 10H ; Call BIOS
; Returns: MODE in AL, COLS in AH, PAGE in BH
MOV MODE_FLAG,AL ; Save mode code for later
MOV AL,AH ; Get COLS to AL
CBW ; Make it a word
MOV CRT_COLS,AX ; and save it
;
; Multiply the screen width by the screen length to get area into AX.
; Multiply by the page number to get upper left offset from the beginning
; of the display buffer. Add to this the difference between the upper left
; and lower right addresses to get the offset from the beginning of the
; buffer to the lower right corner of the current page being displayed.
;
MOV CX,50 ; Assuming 25 rows always and 2 bytes/char
MUL CL ; Get size of screen
MOV SI,AX ; SI will have offset to lower right corner
DEC SI
DEC SI
MOV CL,BH ; Figure page offset
MUL CX ; from display buffer base
MOV DI,AX ; Now have upper left offset in DI
ADD SI,DI ; and lower right in SI
;
; Check argument to see if scroll or blank operation is requested.
; If blank, then do it right away.
;
POP DX ; Get the argument saved on the stack above
BLANKSCREEN:
CLD ; Assume forward direction for now
MOV AX,DX ; Keep a copy of the argument in AX
TEST DX,DX ; Which way to scroll?
JNZ REALSCROLL ; If non-zero, then it is a real scroll
;
; This is a blank screen operation, not a scroll.
; Blank entire screen by specifying no rows or cols for scroll and
; all rows and cols for blank operation.
;
PUSH CRT_COLS ; Blank all columns
MOV AX,25 ; and
PUSH AX ; all rows
XOR BX,BX ; Scroll no rows
XOR BP,BP ; and no columns
JMP COMMON ; Proceed to common scrolling code
;
; A real scroll has been requested. Check the sign of the argument to
; determine which corners the DI and SI registers should point to.
; If the registers must be reversed, then perform STD to reverse direction.
;
REALSCROLL:
JG FORWARD ; If >0 then DI, SI, DF, and DX are ok
XCHG DI,SI ; else assume lower right corner destination.
STD ; Need to set direction flag too.
NEG DX ; Get the absolute value of the argument.
FORWARD:
MOV BP,CRT_COLS ; Get the number of columns into BP.
MOV CX,DX ; Put argument into CX for next check.
SUB CX,256 ; Is the scroll vertical or horizontal?
JG HORIZONTAL ; Horizontal if > 256.
;
; ***** VERTICAL SCROLL CODE *****
;
; Check that # rows is ok. Save parameters on stack for the blank operation
; after scroll. Calculate the distance in bytes to move the data (including
; the sign from the argument), and put result in DX. Continue with common
; scroll code section.
;
MOV BX,25 ; Total number of rows on the screen
SUB BX,DX ; less number moved = number to move.
JLE SETBLANK ; Asked for whole screen or more.
PUSH BP ; Save chars/row for blanking rows later.
PUSH DX ; Save number of rows for blanking too.
MOV CX,160 ; There are 160 bytes per row
IMUL CX ; Get offset for MOVSW
MOV DX,AX ; Source-Destination offset into DX
JMP COMMON ; Proceed to common scrolling code
;
; Set up the registers to do a blank screen operation. DX must be zero and
; SI and DI must be swapped back if already swapped.
;
SETBLANK:
XOR DX,DX ; Set argument to zero.
TEST AX,AX ; Was this a down/right operation?
JGE BLANKSCREEN ; No, go directly to blank screen.
XCHG SI,DI ; Yes, reset SI and DI before
JMP BLANKSCREEN ; proceeding to blank entire screen
;
; ***** HORIZONTAL SCROLL CODE *****
;
; Figure number of columns to move characters by. If too large, then it's
; a blanking operation. Set registers for common code and scroll operation.
;
HORIZONTAL:
SUB BP,CX ; Total cols less num cols moved = # to move
JLE SETBLANK ; Too many cols means blank screen
PUSH CX ; Save number of columns to blank
MOV DX,CX ; Pick up words/row offset
TEST AX,AX ; Check sign of parameter
JG PLUS ; OK
NEG DX ; Get back correct sign
PLUS:
SHL DX,1 ; Change words to bytes
MOV BX,25 ; Number of rows to visit
PUSH BX ; Save rows to blank
;
; ***** COMMON CODE *****
;
; Complete the set up for the scroll by calculating the row offset (bytes
; per row) and setting up DS and ES to point to the display buffer.
;
COMMON:
MOV CX,CRT_COLS ; Calculate row offset: get # cols on screen.
SHL CX,1 ; Convert from words to bytes.
TEST AX,AX ; Get the sign right
JGE ARGPLUS ; by forcing it
NEG CX ; to be the same as AX.
ARGPLUS:
PUSH CX ; Save row offset for blank operation.
MOV AX,0B000H ; Get base segment address for mono display.
CMP MODE_FLAG,7 ; Is this the monochrome adaptor?
JE MONO ; Yes, leave base address alone.
MOV AX,0B800H ; No, set up for color/graphics adaptor.
MONO:
MOV DS,AX ; Use AX to set up DS
MOV ES,AX ; and ES.
;
; Now, DI points to correct corner of screen
; SI points ot the opposite corner
; The DF bit is set properly
; BP = words per row to move
; BX = number of rows to do
; DX = destination-source offset
; DS and ES are set to the correct segment
;
ASSUME DS:NOTHING
;
; Perform the actual scroll here. Get the saved row-to-row distance into
; AX, save the opposite corner value, and set SI correctly for the MOVSW.
; The actual move uses a loop on BX to go from row to row and the
; REP MOVSW instruction to do each row. SI and DI must be saved before doing
; the MOVSW because they are changed by it. Adding AX to the SI and DI sets
; them up for the next row.
;
POP AX ; Get row to row offset.
PUSH AX ; Save for blanking.
PUSH SI ; Save opposite corner for blanking.
MOV SI,DI ; Ready to adjust source by DX.
ADD SI,DX ; Adjust source.
SCROLLOOP:
MOV CX,BP ; Words per row.
PUSH SI
PUSH DI
REP MOVSW ; Move the words.
POP DI
POP SI
ADD SI,AX ; Point to the
ADD DI,AX ; next row.
DEC BX ; Count down.
JG SCROLLOOP ; Loop until all rows are done.
;
; Now must blank rows or columns. The information needed has been saved on
; the stack. Retrieve it. Put the blank character and attribute in AX in
; preparation for the REP STOSW instruction, and set the direction correctly.
; The blank operation is performed one row at a time with the REP STOSW
; instruction. The rows are done with a loop on BX.
;
POP DI ; Get correct corner of the screen.
POP DX ; Get the row offset
POP BX ; and the row count
POP BP ; and the character count.
MOV AX,720H ; 720H is a blank with normal attributes.
CLD ; Assume forward direction for STOSW.
TEST DX,DX ; Is it?
JL BLANKLOOP ; Yes, go ahead.
STD ; No, change direction bit.
BLANKLOOP:
MOV CX,BP ; Pick up the character count.
PUSH DI ; Save DI.
REP STOSW ; Store the blanks in display buffer.
POP DI ; Get DI back.
SUB DI,DX ; Move to the next row.
DEC BX ; Decrement the row count
JG BLANKLOOP ; and keep going until all done.
;
; Scrolling and blanking is complete. Restore saved registers and return.
;
POP ES ; Restore ES register.
POP DS ; Restore DS register.
POP BP ; Restore BP register.
RET ; Return to caller.
SCROLL ENDP
CODE ENDS
END